package tolls;

import avenue.MyWindowEvent;
import avenue.Session;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import javax.swing.JFrame;
import model.Collection;
import model.DBManager;
import model.ProgramRate;
import model.Vehicle;

public class CollectTollForm extends javax.swing.JFrame {

    public CollectTollForm() {
        em = DBManager.em;
        if ( !em.getTransaction().isActive()){
            em.getTransaction().begin();
        }
        String dateFormat = "HH:mm:ss";
        sdf = new SimpleDateFormat(dateFormat);
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        vehicle1 = new model.Vehicle();
        programRate1 = new model.ProgramRate();
        regNumberTF = new javax.swing.JTextField();
        passButton = new javax.swing.JButton();
        cardIdTF = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        payButton = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JSeparator();
        jLabel3 = new javax.swing.JLabel();
        cardBalanceTF = new javax.swing.JTextField();
        jSeparator2 = new javax.swing.JSeparator();
        jLabel4 = new javax.swing.JLabel();
        searchButton = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        messageArea = new javax.swing.JTextArea();
        clearButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        jLabel5 = new javax.swing.JLabel();
        numOfPassesTF = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("Διέλευση Οχήματος");

        passButton.setText("ΔΙΕΛΕΥΣΗ");
        passButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                passButtonActionPerformed(evt);
            }
        });

        jLabel2.setText("Αρ. Κάρτας: ");

        jLabel1.setText("Αρ. Κυκλοφορίας: ");

        payButton.setText("ΠΛΗΡΩΜΗ");
        payButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                payButtonActionPerformed(evt);
            }
        });

        jLabel3.setText("Υπόλοιπο Κάρτας: ");

        cardBalanceTF.setEditable(false);

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, vehicle1, org.jdesktop.beansbinding.ELProperty.create("${cardId.balance}"), cardBalanceTF, org.jdesktop.beansbinding.BeanProperty.create("text"), "balance");
        bindingGroup.addBinding(binding);

        jLabel4.setText("Πεδίο Μηνυμάτων:");

        searchButton.setText("ΑΝΑΖΗΤΗΣΗ");
        searchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchButtonActionPerformed(evt);
            }
        });

        messageArea.setEditable(false);
        messageArea.setColumns(20);
        messageArea.setRows(5);
        jScrollPane1.setViewportView(messageArea);

        clearButton.setText("ΚΑΘΑΡΙΣΜΟΣ");
        clearButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearButtonActionPerformed(evt);
            }
        });

        cancelButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/cancel.gif"))); // NOI18N
        cancelButton.setText("Ακυρο");
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelButtonActionPerformed(evt);
            }
        });

        jLabel5.setText("Πλήθος διελεύσεων τρέχοντα μήνα:");

        numOfPassesTF.setEditable(false);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jSeparator1)
                    .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 801, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jLabel1)
                                    .addComponent(jLabel2))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(regNumberTF, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(cardIdTF, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(61, 61, 61)
                                        .addComponent(searchButton))))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel3)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(cardBalanceTF, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(37, 37, 37)
                                .addComponent(jLabel5)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(numOfPassesTF, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(passButton)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(payButton))
                            .addComponent(cancelButton)
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                                .addGroup(layout.createSequentialGroup()
                                    .addComponent(jLabel4)
                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(clearButton))
                                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 711, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(regNumberTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(cardIdTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(searchButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(cardBalanceTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel5)
                    .addComponent(numOfPassesTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel4)
                    .addComponent(clearButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(passButton)
                    .addComponent(payButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 42, Short.MAX_VALUE)
                .addComponent(cancelButton)
                .addContainerGap())
        );

        bindingGroup.bind();

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
        
        canPass = false;
        canPay = false;
        freePass = false;
        cal = Calendar.getInstance();
        
        // Έλεγχος των δεδομένων εισόδου
        if (regNumberTF.getText().equals("")) {
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Ο αριθμός κυκλοφορίας είναι κενός.\n");
            return;
        } else if (cardIdTF.getText().equals("")) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Ο αριθμός της κάρτας είναι κενός.\n");
            return;
        }
        
        String regNumber = regNumberTF.getText();
        Integer cardId;
        try { 
            cardId = Integer.parseInt(cardIdTF.getText());
        } catch(NumberFormatException ex) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Μη έγκυρος αριθμός κάρτας.\n");
            return;
        }
        
        // Αναζήτησε το όχημα με τον εν λόγω αριθμό πινακίδας και τον εν
        // λόγω αριθμό κάρτας
        Query vehicleQuery = em.createQuery("select v from Vehicle v where "
                + "v.regNumber = :regNumber and v.cardId.id = :cardId");
        
        vehicleQuery.setParameter("regNumber", regNumber);
        vehicleQuery.setParameter("cardId", cardId);
        
        try { 
            // Εκτέλεση της επερώτησης
            vehicle1 = (Vehicle) vehicleQuery.getSingleResult();
            cardBalanceTF.setText(vehicle1.getCardId().getBalance().toString());
        } catch(NoResultException ex) { 
            // Το όχημα δεν βρέθηκε
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Ο συνδυασμός οχήματος/κάρτας δεν βρέθηκε.\n");
            return;
        } catch(NonUniqueResultException ex) { 
            // Βρέθηκαν παραπάνω του ενός αποτελέσματα
            messageArea.append("(" + sdf.format(cal.getTime()) 
                        + "): Δεν επιστράφηκε μόνο ένα αποτέλεσμα!\n");
            return;
        }
        
        // Αναζήτησε την χρεώση που αντιστοιχεί στον τρέχων σταθμό, για το
        // τρέχον είδος οχήματος και για το εν λόγω πρόγραμμα
        Query programRateQuery = em.createQuery("select pr from ProgramRate pr where "
                + "pr.stationId = :stationId and pr.categoryId = :categoryId and "
                + "pr.programId = :programId");
        programRateQuery.setParameter("stationId", Session.loginUser.getStationId());
        programRateQuery.setParameter("categoryId", vehicle1.getCategoryId());
        programRateQuery.setParameter("programId", vehicle1.getCardId().getProgramId());
        
        try { 
            // Εκτέλεση της επερώτησης
            programRate1 = (ProgramRate) programRateQuery.getSingleResult();
        } catch(Exception ex) { 
            // Πρόβλημα κατά την ανάκτηση της χρέωσης
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Ο πίνακας χρεώσεων του σταθμού δεν μπορεί να βρεθεί!\n");
            return;
        }
        
        Query numOfPassesQuery = em.createQuery("select c from Collection c where "
                + "c.cardId = :cardId");
        numOfPassesQuery.setParameter("cardId", vehicle1.getCardId());
        
        List<Collection> collections;
        try { 
             collections = numOfPassesQuery.getResultList();
        } catch(Exception ex) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Ο αριθμός διελεύσεων του οχήματος δεν μπορεί να βρεθεί!\n");
            return;
        }
        
        Integer numOfPasses = 0;
        Calendar rightNow = Calendar.getInstance();
        Calendar tmp = Calendar.getInstance();
        for (Collection c : collections) { 
             tmp.setTime(c.getPassTimestamp());
             if (rightNow.get(Calendar.MONTH) == tmp.get(Calendar.MONTH))
                 numOfPasses++;
        }
        
        numOfPassesTF.setText(numOfPasses.toString());
        
        canPay = true;
        
        if (vehicle1.getCardId().getProgramId().getPayLimit() < numOfPasses) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Το πρόγραμμα της κάρτας έφτασε τον μέγιστο αριθμό "
                        + "χρεωθέντων διελεύσεων (" 
                        + vehicle1.getCardId().getProgramId().getPayLimit().intValue() + 
                        "). Η διέλευση δεν χρεώνεται.\n");
            freePass = true;
            canPass = true;
        } else if (vehicle1.getCardId().getBalance().doubleValue() >= 
            programRate1.getRate().doubleValue()) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Το υπόλοιπο επαρκεί για την διέλευση (" 
                        + programRate1.getRate().doubleValue() + " ευρώ). "
                        + "Τα πλήκτρα διέλευσης και πληρωμής ενεργοποιούνται.\n");
            canPass = true;
        } else { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Το υπόλοιπο δεν επαρκεί για την διέλευση!\n");
            canPass = false;
        }
        
        if (vehicle1.getCardId().getBalance().doubleValue() < 5.00) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Το υπόλοιπο της κάρτας είναι χαμηλό (κάτω από 5 ευρώ). "
                        + "Ο πελάτης μπορεί να φορτίσει την κάρτα αν το επιθυμεί.\n");
        }
        
    }//GEN-LAST:event_searchButtonActionPerformed

    private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed
        
        messageArea.setText("");
        
    }//GEN-LAST:event_clearButtonActionPerformed

    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
        
        em.getTransaction().rollback();
        em.getTransaction().begin();
        dispose();
        
    }//GEN-LAST:event_cancelButtonActionPerformed

    private void passButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_passButtonActionPerformed
        
        cal = Calendar.getInstance();
        
        if (!canPass) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Το πλήκτρο διέλευσης είναι απενεργοποιημένο. "
                      + "Αναζητήστε ένα όχημα για να το ενεργοποιήσετε.\n");
            return;
        }
        
        double tollCollected;
        if (freePass) { 
            tollCollected = 0;
        } else { 
            tollCollected = programRate1.getRate().doubleValue();
            double oldBalance = vehicle1.getCardId().getBalance();
            vehicle1.getCardId().setBalance(oldBalance - tollCollected);
        }
        
        Collection col = new Collection();
        col.setCardId(vehicle1.getCardId());
        col.setTollCollected(new BigDecimal(tollCollected));
        col.setPassTimestamp(new Date());
        col.setStationId(Session.loginUser.getStationId());
        em.persist(col);
        
        em.getTransaction().commit();
        em.getTransaction().begin();
        
        dispose();
        
    }//GEN-LAST:event_passButtonActionPerformed

    private void payButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_payButtonActionPerformed
        
        cal = Calendar.getInstance();
        
        if (!canPay) { 
            messageArea.append("(" + sdf.format(cal.getTime()) + 
                        "): Το πλήκτρο πληρωμής είναι απενεργοποιημένο. "
                      + "Αναζητήστε ένα όχημα για να το ενεργοποιήσετε.\n");
            return;
        }

        PaymentForm pForm = new PaymentForm(vehicle1);
        pForm.setVisible(true);
        thisFrame=this;
        thisFrame.setEnabled(false);
        //************
        pForm.addWindowListener(new WindowListener() {
            public void windowClosed(WindowEvent arg0) {
                System.out.println("Window close event occur");
                if (((MyWindowEvent)arg0).exitAndSave){
                    cardBalanceTF.setText(vehicle1.getCardId().getBalance().toString());
                    thisFrame.setEnabled(true);
                    canPass = true;
                }
                else{
                    thisFrame.setEnabled(true);
                }
            }
            public void windowActivated(WindowEvent arg0) {
                System.out.println("Window Activated");
            }
            public void windowClosing(WindowEvent arg0) {
                System.out.println("Window Closing");
            }
            public void windowDeactivated(WindowEvent arg0) {
                System.out.println("Window Deactivated");
            }
            public void windowDeiconified(WindowEvent arg0) {
                System.out.println("Window Deiconified");
            }
            public void windowIconified(WindowEvent arg0) {
                System.out.println("Window Iconified");
            }
            public void windowOpened(WindowEvent arg0) {
                System.out.println("Window Opened");
            }
        });
        
    }//GEN-LAST:event_payButtonActionPerformed

    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cancelButton;
    private javax.swing.JTextField cardBalanceTF;
    private javax.swing.JTextField cardIdTF;
    private javax.swing.JButton clearButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JTextArea messageArea;
    private javax.swing.JTextField numOfPassesTF;
    private javax.swing.JButton passButton;
    private javax.swing.JButton payButton;
    private model.ProgramRate programRate1;
    private javax.swing.JTextField regNumberTF;
    private javax.swing.JButton searchButton;
    private model.Vehicle vehicle1;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
    EntityManager em;
    JFrame thisFrame;
    private boolean canPass = false;
    private boolean canPay = false;
    private boolean freePass = false;
    private Calendar cal;
    private SimpleDateFormat sdf;

}
